package AIbyDavid;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Random;

public class Population {
	Random rand;
	ArrayList<GeneticCode> population = new ArrayList<GeneticCode>();
	ArrayList<Double> fitness;

	public Population() {
		rand = new Random();
		for (int i = 0; i < 10; i++) {
			population.add(new GeneticCode());
		}
	}

	public boolean nextIteration() {
		GeneticCode sol=calculateFitnessValues();
		if (sol==null) {
			ArrayList<GeneticCode> parents = selectParents();
			population = makeChildren(parents);

			population = mutate(population);
			// System.out.println(children);
			// System.out.println(children.size());

			// population=new ArrayList<GeneticCode>();
			// for(int f=0;f<10;f++){
			// population.add(parents.get(f));
			// }
			for (GeneticCode g : population) {
				g.evaluateCode();
			}
		}else{
			System.out.println("Solution found, Genotype: "+sol.code);
			return true;
		}
		return false;
	}

	private ArrayList<GeneticCode> mutate(ArrayList<GeneticCode> population2) {
		for (GeneticCode g : population2) {
			g.mutate();
		}
		return population2;
	}

	private ArrayList<GeneticCode> makeChildren(ArrayList<GeneticCode> parents) {
		ArrayList<GeneticCode> children = new ArrayList<GeneticCode>();
		for (int i = 0; i < 20; i += 2) {
			children.add(parents.get(i).merge(parents.get(i + 1)));
		}
		return children;
	}

	private ArrayList<GeneticCode> selectParents() {
		ArrayList<GeneticCode> parents = new ArrayList<GeneticCode>();
		for (int i = 0; i < 20; i++) {
			double d = rand.nextDouble();
			double tmp = 0;
			for (int j = 0; j < 10; j++) {
				tmp += fitness.get(j);
				if (d <= tmp) {
					parents.add(population.get(j));
					break;
				} else if (j == 10) {
					parents.add(population.get(j));
				}
			}
		}
		return parents;
	}

	private GeneticCode calculateFitnessValues() {
		fitness = new ArrayList<Double>();
		Collections.sort(population);
		long sum = 0;
		for (GeneticCode g : population) {
			sum += g.codeFitness;
		}
		for (GeneticCode g : population) {
			double chance = ((double) g.codeFitness / (double) sum);
			fitness.add(chance);
			if (chance == 0) {// function is minimized
				return g;
			}

		}
		Collections.reverse(population);
		return null;

	}

	public String toString() {
		StringBuilder sb = new StringBuilder();
		for (GeneticCode g : population) {
			sb.append(g.toString() + "\n");
		}
		return sb.toString();
	}
}